﻿using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;

namespace iTool.Common
{
    public static class iBox
    {
        static iBox()
        {
            lock (ProviderLock)
            {
                if (!servicePairs.ContainsKey("default"))
                {
                    var collection = new ServiceCollection();
                    servicePairs.Add("default", collection);
                }
            }
        }

        #region Parameter

        /// <summary>
        /// 服务盒子
        /// </summary>
        static Dictionary<string, IServiceCollection> servicePairs = new Dictionary<string, IServiceCollection>();

        /// <summary>
        /// 服务容器
        /// </summary>
        static ConcurrentDictionary<string, IServiceProvider> providerPairs = new ConcurrentDictionary<string, IServiceProvider>();

        /// <summary>
        /// 局部锁
        /// </summary>
        static object ProviderLock { get; set; } = new object();

        #endregion

        /// <summary>
        /// 获取服务
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="model"></param>
        /// <returns></returns>
        public static T GetService<T>(string providerName = "default") where T : class
        {
            try
            {
                if (providerPairs.TryGetValue(providerName, out IServiceProvider serviceProvider))
                {
                    var provider = serviceProvider.GetService<T>();
                    return provider;
                }
                else if (servicePairs.TryGetValue(providerName, out IServiceCollection serviceCollection))
                {
                    lock (ProviderLock)
                    {
                        if (!providerPairs.TryGetValue(providerName, out serviceProvider))
                        {
                            serviceProvider = serviceCollection.BuildServiceProvider();
                            providerPairs.TryAdd(providerName, serviceProvider);
                        }
                    }
                }

                return serviceProvider?.GetService<T>();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public static object GetService(Type type, string providerName = "default")
        {
            try
            {
                if (providerPairs.TryGetValue(providerName, out IServiceProvider serviceProvider))
                {
                    var provider = serviceProvider.GetService(type);
                    return provider;
                }
                else if (servicePairs.TryGetValue(providerName, out IServiceCollection serviceCollection))
                {
                    lock (ProviderLock)
                    {
                        if (!providerPairs.TryGetValue(providerName, out serviceProvider))
                        {
                            serviceProvider = serviceCollection.BuildServiceProvider();
                            providerPairs.TryAdd(providerName, serviceProvider);
                        }
                    }
                }

                return serviceProvider?.GetService(type);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public static IServiceCollection GetServiceCollection(string providerName = "default", IServiceCollection services = null)
        {
            lock (ProviderLock)
            {
                if (services != null)
                {
                    providerPairs.TryRemove(providerName, out _);

                    if (servicePairs.ContainsKey(providerName))
                    {
                        servicePairs[providerName] = services;
                    }
                    else
                    {
                        servicePairs.Add(providerName, services ?? new ServiceCollection());
                    }
                }
                else if (!servicePairs.ContainsKey(providerName))
                {
                    servicePairs.Add(providerName, services ?? new ServiceCollection());
                }
                return servicePairs[providerName];
            }
        }

        public static string RegisterServiceProvider(IServiceProvider serviceProvider, string providerName = "default")
        {
            lock (ProviderLock)
            {
                providerPairs.AddOrUpdate(providerName, serviceProvider, (a, b) => serviceProvider);
            }
            return string.Empty;
        }

        public static void Clear(string providerName = "default")
        {
            lock (ProviderLock)
            {
                if (servicePairs.ContainsKey(providerName))
                {
                    var collection = new ServiceCollection();
                    servicePairs[providerName] = collection;
                    providerPairs.TryRemove(providerName, out _);
                }
            }
        }
    }
}
